﻿using DotSpatial.Data;
using DotSpatial.Projections;
using DotSpatial.Symbology;
using DotSpatial.Topology;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Data.SqlClient;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace Demo
{
    public partial class Form1 : Form
    {
        #region 构造函数
        public Form1()
        {
            InitializeComponent();
        }
        #endregion

        #region 变量
        private DotSpatial.Controls.Map map;
        DotSpatial.Controls.MapPointLayer pointLayer;
        DotSpatial.Controls.MapImageLayer imgLayer;

        IFeatureCategory _oldCategory = null;//未选择前样式
        IFeatureCategory _selectedCategory = null;//选择后样式
        bool _mousedown = false;

        IFeature seletedFeature = null;//选中的Feature

        DotSpatial.Controls.CustomMapFunction _customMethod;
        #endregion

        #region 事件
        private void Form1_Load(object sender, EventArgs e)
        {
            this.map = new DotSpatial.Controls.Map();
            this.Controls.Add(this.map);
            this.map.Dock = DockStyle.Fill;
            //阻止弹出坐标投影选择框
            this.map.MapFrame.ProjectionModeDefine = DotSpatial.Controls.ActionMode.Never;
            //加载图片底图
            this.loadImage();
            //激活地图缩放操作
            this.activeCustomMapFunction();
            //构造FeatureSet
            FeatureSet fs = new FeatureSet(FeatureType.Point);// Model.PointModel.FindAllFeature());该方法有问题，所以遍历添加Feature
            if (!fs.DataTable.Columns.Contains("Datakey"))
            {
                fs.DataTable.Columns.Add("Datakey", typeof(String));
            }
            this.pointLayer = new DotSpatial.Controls.MapPointLayer(fs);
            Model.PointModel.FindAllFeature(ref fs);
            this.map.MapFrame.DrawingLayers.Add(this.pointLayer);
            //设置样式
            this.setScheme();
            this.map.MouseDown += Map_MouseDown;
        }

        private void setScheme()
        {
            //构造点样式方案
            PointScheme ps = new PointScheme();
            //ps.EditorSettings.ClassificationType = ClassificationType.UniqueValues;
            //点样式类别：FID = 0 的点样式为红色星星符号
            PointCategory pc = new PointCategory(Color.Red, DotSpatial.Symbology.PointShape.Star, 15);
            pc.FilterExpression = "[FID] = 0";
            ps.AddCategory(pc);
            //点样式类别：FID > 0 的点样式为图片
            Image icon = System.Drawing.Image.FromFile(Application.StartupPath + "\\Resource\\position.png");
            pc = new PointCategory(icon, 20);
            pc.FilterExpression = "[FID] >0";
            ps.AddCategory(pc);
            //将点样式方案应用到点图层
            this.pointLayer.ApplyScheme(ps);
            this.map.Refresh();
        }

        private void Map_MouseDown(object sender, MouseEventArgs e)
        {
            _mousedown = true;
        }

        private void activeCustomMapFunction()
        {
            _customMethod = new DotSpatial.Controls.CustomMapFunction(this.map);
            this.map.ActivateMapFunction(_customMethod);
            //鼠标移动事件
            _customMethod.OnCustomMousMove = new DotSpatial.Controls.CustomMapFunction.CustomMethodDelegate((e) =>
            {
                if (this.pointLayer == null)
                {
                    return;
                }
                IFeature f = null;

                if (this.seletedFeature != null)
                {
                    this.pointLayer.SetCategory(this.seletedFeature, _oldCategory);
                    this.map.Refresh();
                }

                DotSpatial.Topology.Coordinate c = e.GeographicLocation;
                f = this.pointLayer.FeatureSet.Features.ToList().Find((fea) => { return fea.Coordinates[0].X > c.X - 10 && fea.Coordinates[0].X < c.X + 10 && fea.Coordinates[0].Y > c.Y - 10 && fea.Coordinates[0].Y < c.Y + 10; });
                if (f != null)
                {
                    _oldCategory = this.pointLayer.GetCategory(f);
                    //if (_selectedCategory == null)
                    //{
                    //    _selectedCategory = _oldCategory.Copy();
                    //    _selectedCategory.Symbolizer.SetOutline(Color.White, 3);
                    //}
                    _selectedCategory = _oldCategory.Copy();
                    _selectedCategory.Symbolizer.SetOutline(Color.White, 2);

                    this.pointLayer.SetCategory(f, _selectedCategory);
                    this.seletedFeature = f;
                    this.Cursor = Cursors.Hand;
                    this.map.Refresh();
                }
                else if (!_mousedown)
                {
                    this.seletedFeature = null;
                }
                this.tslPosition.Text = string.Format("当前鼠标位置：X={0}，Y={1}", c.X, c.Y);

            });

            //移动点鼠标移动操作
            _customMethod.OnDraggingMousMove = new DotSpatial.Controls.CustomMapFunction.CustomMethodDelegate((e) =>
            {
                if (this.pointLayer == null)
                {
                    return;
                }
                if (this.seletedFeature != null)//此时为鼠标拖动状态
                {
                    DotSpatial.Topology.Coordinate c = e.GeographicLocation;
                    this.seletedFeature.Coordinates.Clear();
                    this.seletedFeature.Coordinates.Add(c);
                    e.Map.Refresh();
                }
            });

            //新增点鼠标释放操作
            _customMethod.OnInsertingMousUp = new DotSpatial.Controls.CustomMapFunction.CustomMethodDelegate((e) =>
            {
                _mousedown = false;
                DotSpatial.Topology.Coordinate c = e.GeographicLocation;
                DotSpatial.Topology.Point pt = new DotSpatial.Topology.Point(c);
                Feature f = new Feature(pt);
                var table = new System.Data.DataTable();
                f.DataRow = table.NewRow();
                if (!f.DataRow.Table.Columns.Contains("Datakey"))
                {
                    f.DataRow.Table.Columns.Add("Datakey", typeof(String));
                }
                if (!f.DataRow.Table.Columns.Contains("FID"))
                {
                    f.DataRow.Table.Columns.Add("FID", typeof(int));
                }
                this.pointLayer.FeatureSet.Features.Add(f);//先加入FeatureSet才能获得Fid
                f.DataRow.BeginEdit();
                f.DataRow["Datakey"] = Guid.NewGuid().ToString("N");
                f.DataRow["FID"] = f.Fid;
                f.DataRow.EndEdit();
                this.insertPoint(f);
                this.setScheme();
            });

            //移动点鼠标释放操作
            _customMethod.OnDraggingMousUp = new DotSpatial.Controls.CustomMapFunction.CustomMethodDelegate((e) =>
            {
                _mousedown = false;
                if (this.seletedFeature != null)
                {
                    DotSpatial.Topology.Coordinate c = e.GeographicLocation;
                    this.seletedFeature.Coordinates.Clear();
                    this.seletedFeature.Coordinates.Add(c);
                    if (_oldCategory != null)
                    {
                        this.pointLayer.SetCategory(this.seletedFeature, _oldCategory);
                        this.map.Refresh();
                    }
                    this.map.Refresh();
                    this.updatePoint(this.seletedFeature);
                    this.seletedFeature = null;

                }
            });

            //删除点鼠标释放操作
            _customMethod.OnDeletingMouseUp = new DotSpatial.Controls.CustomMapFunction.CustomMethodDelegate((e) =>
           {
               _mousedown = false;
               if (this.seletedFeature != null)
               {
                   if (MessageBox.Show("确认删除该对象吗？") == DialogResult.OK)
                   {
                       this.deletePoint(this.seletedFeature);
                       this.pointLayer.DataSet.Features.Remove(this.seletedFeature);
                   }
                   this.map.Refresh();
                   this.seletedFeature = null;
               }
           });

            //鼠标双击操作（在点增删改都不可用时触发）
            _customMethod.OnCustomDoubleClick = new DotSpatial.Controls.CustomMapFunction.CustomMethodDelegate((e) =>
            {
                if (this.seletedFeature != null)
                {
                    AttributeForm af = new AttributeForm(this.seletedFeature);
                    af.ShowDialog();
                }

            });
        }

        private void tsbAdd_Click(object sender, EventArgs e)
        {
            this.tsbMove.Text = "移动";
            this.tsbDelete.Text = "删除";
            if (this.tsbAdd.Text == "新增")
            {
                this._customMethod.EnableMethod(DotSpatial.Controls.MethodEnum.Insert);
                this.tsbAdd.Text = "结束新增";
            }
            else
            {
                this._customMethod.DisenableMethod();
                this.tsbAdd.Text = "新增";
            }
        }

        private void tsbMove_Click(object sender, EventArgs e)
        {
            this.tsbAdd.Text = "新增";
            this.tsbDelete.Text = "删除";
            if (this.tsbMove.Text == "移动")
            {
                this._customMethod.EnableMethod(DotSpatial.Controls.MethodEnum.Drag);
                this.tsbMove.Text = "结束移动";
            }
            else
            {
                this._customMethod.DisenableMethod();
                this.tsbMove.Text = "移动";
            }

        }

        private void tsbDelete_Click(object sender, EventArgs e)
        {
            this.tsbAdd.Text = "新增";
            this.tsbMove.Text = "移动";
            if (this.tsbDelete.Text == "删除")
            {
                this._customMethod.EnableMethod(DotSpatial.Controls.MethodEnum.Delete);
                this.tsbDelete.Text = "结束删除";
            }
            else
            {
                this._customMethod.DisenableMethod();
                this.tsbDelete.Text = "删除";
            }
        }

        private void tsbLoadImg_Click(object sender, EventArgs e)
        {
            OpenFileDialog openfile = new OpenFileDialog();
            openfile.Title = " 请选择地图图片";
            openfile.Filter = "地图图片 (*.jpg;*.bmp;*png)|*.jpeg;*.jpg;*.bmp;*.png|AllFiles(*.*)|*.*";
            if (DialogResult.OK == openfile.ShowDialog())
            {
                try
                {
                    // 读成二进制
                    byte[] bytes = File.ReadAllBytes(openfile.FileName);
                    //保存到数据库
                    Model.ImageModel imageM = new Model.ImageModel();
                    imageM.Value = bytes;
                    imageM.Insert();

                    //由于imageLayer直接加载byte[]有问题，所以先存成tmp图片
                    // this.addImgLayer(img);
                    Image img = System.Drawing.Image.FromStream(new MemoryStream(bytes));
                    this.addImgLayer(openfile.FileName);
                }
                catch (Exception ex)
                {
                    MessageBox.Show(ex.Message);
                }
            }
        }
        private void tsbClearPoint_Click(object sender, EventArgs e)
        {
            if (MessageBox.Show("确认清空所有点吗？") == DialogResult.OK)
            {
                Model.PointModel.Clear();
                this.pointLayer.FeatureSet.Features.Clear();
                this.map.Refresh();
            }
        }
        #endregion

        #region 内部方法
        private void loadImage()
        {
            Model.ImageModel imgM = Model.ImageModel.Get();
            if (imgM != null)
            {
                //由于imageLayer直接加载byte[]有问题，所以先存成tmp图片
                // this.addImgLayer(img);
                var bytes = imgM.Value;
                Image img = System.Drawing.Image.FromStream(new MemoryStream(bytes));
                string fileName = Config.TmpPath + "\\tmp.jpg";
                File.WriteAllBytes(fileName, bytes);
                this.addImgLayer(fileName);
            }
        }

        /// <summary>
        /// 该方法有问题，暂时放弃
        /// </summary>
        /// <param name="img"></param>
        private void addImgLayer(Image img)
        {
            if (this.imgLayer != null && this.map.Layers.Contains(this.imgLayer))
            {
                this.map.Layers.Remove(this.imgLayer);
                this.imgLayer.Dispose();
                this.imgLayer = null;
            }
            DotSpatial.Data.InRamImageData imgData = new InRamImageData(img);
            this.imgLayer = new DotSpatial.Controls.MapImageLayer(imgData);
            this.map.Layers.Add(this.imgLayer);
            //this.map.SetBounds(0, 0, imgData.Width, imgData.Height);
            this.map.Invalidate();
        }
        private void addImgLayer(string imgName)
        {
            if (this.imgLayer != null && this.map.Layers.Contains(this.imgLayer))
            {
                this.map.Layers.Remove(this.imgLayer);
                this.imgLayer.Dispose();
                this.imgLayer = null;
            }
            DotSpatial.Data.InRamImageData imgData = new InRamImageData(imgName);
            this.imgLayer = new DotSpatial.Controls.MapImageLayer(imgData);
            this.map.Layers.Add(this.imgLayer);
            //this.map.SetBounds(0, 0, imgData.Width, imgData.Height);
            this.map.Refresh();
        }

        private void insertPoint(IFeature feature)
        {
            if (feature != null && feature.FeatureType == FeatureType.Point)
            {
                if (feature.DataRow.Table.Columns.Contains("Datakey"))
                {
                    Model.PointModel pm = new Model.PointModel();
                    pm.X = (float)feature.Coordinates[0].X;
                    pm.Y = (float)feature.Coordinates[0].Y;
                    pm.Datakey = feature.DataRow["Datakey"] == null ? "" : feature.DataRow["Datakey"].ToString();
                    pm.Insert();
                }
            }
        }
        private void updatePoint(IFeature feature)
        {
            if (feature != null && feature.FeatureType == FeatureType.Point)
            {
                if (feature.DataRow.Table.Columns.Contains("Datakey"))
                {
                    Model.PointModel pm = Model.PointModel.FindByDatakey(feature.DataRow["Datakey"].ToString());
                    if (pm != null)
                    {
                        pm.X = (float)feature.Coordinates[0].X;
                        pm.Y = (float)feature.Coordinates[0].Y;
                        pm.Update();
                    }

                }
            }
        }

        private void deletePoint(IFeature feature)
        {
            if (feature != null && feature.FeatureType == FeatureType.Point)
            {
                if (feature.DataRow.Table.Columns.Contains("Datakey"))
                {
                    Model.PointModel pm = Model.PointModel.FindByDatakey(feature.DataRow["Datakey"].ToString());
                    if (pm != null)
                    {
                        pm.Remove();
                    }

                }
            }
        }

        #endregion
    }
}
